package org.hibernate.util;

import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.sqlite.SQLiteConfig;

/**
 * Esta clase fué modificada a partir del template original de Hibernate Utility.
 * En lugar de devolver la session factory para obtener de alli la sesión, la 
 * clase inicializa y devuelve una sesión unica (Singleton pattern) para toda
 * la aplicación. Este patrón es usado ya que se trata de una base de datos 
 * SQLite para un solo usuario, por lo que no es necesario tener en cuenta las
 * precauciones tomadas en casos de bd grandes y con muchos usuarios.
 *
 * @author kiira
 */
public class HibernateUtil {
    /** Session Factory de donde se crean las sesiones. */
    private static final SessionFactory sessionFactory;
    /** Configuración de SQLite para habilitar las foreign keys. */
    private static final SQLiteConfig config;
    /** Dirección de la base de datos a conectarse. */
    private static final String connectionString;
    /** Última sesión activa generada por esta clase. */
    private static Session currentSesion;

    /* Constructor estático que se encarga de:
     * - Inicializar la session factory a partir del archivo de configuración de 
     *   hibernate y de las anotaciones en las entidades generadas.
     * - Inicializar la configuración de SQLite para manejar claves foráneas.
     */
    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
                       
            //creamos la config de sqlite para crear conexiones
            config = new SQLiteConfig();
            config.enforceForeignKeys( true );
            
            //seteamos la string de conexion
            connectionString = "jdbc:sqlite:data/bd";
            
        } catch ( Throwable ex ) {
            // Log the exception. 
            System.err.println( "Initial SessionFactory creation failed." + ex );
            throw new ExceptionInInitializerError( ex );
            
        }
        
    }//end constructor estatico
    
    /**
     * Inicializa hibernate.
     */
    public static void initialize() {
        getCurrentSession();
        
    }//end método initialize
    
    /**
     * Ciera la sesión con la base de datos.
     */
    public static void end() {
        currentSesion.close();
        
    }//end método end

    /**
     * Obtiene, de ser necesario, y devuelve una {@code Sesion} de hibernate para ser
     * utilizada en la aplicación.
     * @return sesión de hibernate activa.
     */
    public static Session getCurrentSession() {
        if ( currentSesion == null || !currentSesion.isOpen() ) 
            try {                
                //obtenemos una nueva sesion que sera usada por toda la aplicación
                currentSesion = sessionFactory.openSession(
                        config.createConnection( connectionString ) );
                
                //seteamos el flush mode a commit para evitar problemas
                currentSesion.setFlushMode( FlushMode.COMMIT );
                
            } //end if
            catch ( SQLException ex ) {
                Logger.getLogger( HibernateUtil.class.getName() ).log( 
                        Level.SEVERE, "No se pudo abrir la base de datos.",
                        ex );

            }
        
        return currentSesion;

    }//end método getCurrentSession

}//end clase HibernateUtil
